package org.uniexception.util;
import org.uniexception.exception.UserDefinedCommonExceptionInterface;
import org.uniexception.exception.UserDefinedException;

import java.lang.Throwable;
import java.lang.reflect.Constructor;

/**
 * helper for handle excpetion
 */
public class UniExceptionUtil {
    //limit max  string length
    private static int max_stacktrace_lenth = 1024;

    /**
     * get string from original excpetion for  return to the front end to display to
     * @throwable original excpetion
     */
    public   static String getStacktraceStr(Throwable throwable)
    {
        StringBuffer strBuf =  new StringBuffer(throwable.getMessage()).append("\n");
        StackTraceElement[] stackTraceElements =  throwable.getStackTrace();
       if(stackTraceElements!= null && stackTraceElements.length>0)
       {
           for(int idx = 0;idx<stackTraceElements.length;++idx)
           {
               strBuf.append("\tat " ).append(stackTraceElements[idx].toString()).append("\n");
               if(strBuf.length()>max_stacktrace_lenth)
               {break;}
           }
       }

        return strBuf.toString();
    }

    /**
     * the handle to deal exception for caller.
     * if a exception has been handle,return it,or,create new UserDefinedException
     * @throwable original excpetion
     */
    public   static <E  extends  UserDefinedCommonExceptionInterface>  E handleException(Throwable throwable)
    {
        if(throwable instanceof UserDefinedCommonExceptionInterface)
        {
            return  (E)throwable;
        }
        else
        {
          return (E)(new UserDefinedException(throwable));
        }

    }
    /**
     * the handle to deal exception for caller.
     * if a exception has been handle,return it,or,create new UserDefinedException
     * @throwable original excpetion
     */
    public   static <E  extends  UserDefinedCommonExceptionInterface>  E handleException(Throwable throwable,String useMsg)
    {
        if(throwable instanceof UserDefinedCommonExceptionInterface)
        {
            return  (E)throwable;
        }
        else
        {
            return (E)(new UserDefinedException(throwable,useMsg));
        }

    }

    /**
     * the handle to deal exception for caller.
     * if a exception has been handle,return it,or,create new UserDefinedException
     * @throwable original excpetion
     */
    public   static <E  extends  UserDefinedCommonExceptionInterface>  E handleException(Throwable throwable,String useMsg,Object... params)
    {
        if(throwable instanceof UserDefinedCommonExceptionInterface)
        {
            return  (E)throwable;
        }
        else
        {
            return (E)(new UserDefinedException(throwable, useMsg,params));
        }

    }




    /**
     * the handle to deal exception for caller with generic param.
     * if a exception has been handle,return it,or,create new UserDefinedException
     * @cls user's new exception types
     * @throwable original excpetion
     */
    public   static <E  extends  UserDefinedCommonExceptionInterface>  E handleExceptionGeneric(Class<UserDefinedCommonExceptionInterface> cls,Throwable throwable)
    {
        if(throwable instanceof UserDefinedCommonExceptionInterface)
        {
            return  (E)throwable;
        }
        else
        {
            try {
                Constructor<?> construct = cls.getConstructor(Throwable.class);
                return (E)(construct.newInstance(throwable));
            }
            catch(Throwable e)
            {
                e.printStackTrace();
                return (E)(new UserDefinedException(throwable));
            }


        }

    }


    public   static <E  extends  UserDefinedCommonExceptionInterface>  E handleExceptionGeneric(Class<UserDefinedCommonExceptionInterface> cls,Throwable throwable,String useMsg)
    {
        if(throwable instanceof UserDefinedCommonExceptionInterface)
        {
            return  (E)throwable;
        }
        else
        {
            try {
                Constructor<?> construct = cls.getConstructor(Throwable.class,String.class);
                return (E)(construct.newInstance(throwable,useMsg));
            }
            catch(Throwable e)
            {
                e.printStackTrace();
                return (E)(new UserDefinedException(throwable,useMsg));
            }


        }

    }


    public   static <E  extends  UserDefinedCommonExceptionInterface>  E handleExceptionGeneric(Class<UserDefinedCommonExceptionInterface> cls,Throwable throwable,String useMsg,Object... params)
    {
        if(throwable instanceof UserDefinedCommonExceptionInterface)
        {
            return  (E)throwable;
        }
        else
        {
            try {
                Constructor<?> construct = cls.getConstructor(Throwable.class,String.class,Object[].class);
                return (E)(construct.newInstance(throwable,useMsg,params));
            }
            catch(Throwable e)
            {
                e.printStackTrace();
                return (E)(new UserDefinedException(throwable,useMsg,params));
            }


        }

    }
}
